//
//	MiscClockView.m -- a simple view class for displaying date/time
//		Written by Scott Anguish Copyright (c) 1993 by Scott Anguish.
//				Version 1.2.  All rights reserved.
//
//		This notice may not be removed from this source code.
//
//	This object is included in the MiscKit by permission from the author
//	and its use is governed by the MiscKit license, found in the file
//	"LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
//	for a list of all applicable permissions and restrictions.
//	

#import <sys/time.h>	

#import "MiscClockView.h"

@interface MiscClockView(private)
- _setUp;
@end

@implementation MiscClockView


#define Misc_BuildImage(a, b, c, d, e) 	NXSetRect(theRect, (b), (c), (d), (e)); \
	a = [[NXImage alloc] initFromImage:theImage rect:theRect];


+ initialize
{
    	[MiscClockView setVersion:3];
	return self;
}


- _setUp
{
char           buf[MAXPATHLEN + 1] = "";
NXRect         rectStorage, *theRect = &rectStorage;
NXSize         oneSize, twoSize;

	if (theImage) return self; // don't want to leak!

	[[NXBundle bundleForClass:[self class]] getPath:buf forResource:"MiscClockStuff" ofType:"tiff"];
	theImage = [[NXImage alloc] initFromFile:buf];


 /* Yes this is ugly, and there is alot of extra junk in here, but to a
  * large degree at this point I didn't know where else to store these
  * co-ordinates where I wouldn't loose them! */

	Misc_BuildImage (imageA, 65.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (imageP, 74.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (DigitalNumbers[1], 89.0, 0.0, 4.0, 11.0);
	Misc_BuildImage (DigitalNumbers[2], 93.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (DigitalNumbers[3], 104.0, 0.0, 8.0, 11.0);
	Misc_BuildImage (DigitalNumbers[4], 112.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (DigitalNumbers[5], 121.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (DigitalNumbers[6], 130.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (DigitalNumbers[7], 140.0, 0.0, 8.0, 11.0);
	Misc_BuildImage (DigitalNumbers[8], 148.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (DigitalNumbers[9], 157.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (DigitalNumbers[0], 166.0, 0.0, 9.0, 11.0);
	Misc_BuildImage (imageColon, 175.0, 0.0, 3.0, 11.0);
	Misc_BuildImage (imageAM, 179.0, 0.0, 12.0, 6.0);
	Misc_BuildImage (imagePM, 192.0, 0.0, 11.0, 6.0);

	Misc_BuildImage (DayNames[1], 0, 65, 19, 5);
	Misc_BuildImage (DayNames[2], 0, 59, 19, 5);
	Misc_BuildImage (DayNames[3], 0, 53, 19, 5);
	Misc_BuildImage (DayNames[4], 0, 47, 19, 5);
	Misc_BuildImage (DayNames[5], 0, 41, 19, 5);
	Misc_BuildImage (DayNames[6], 0, 35, 19, 5);
	Misc_BuildImage (DayNames[0], 0, 29, 19, 5);

	Misc_BuildImage (MonthNames[0], 40, 66, 22, 5);
	Misc_BuildImage (MonthNames[1], 40, 60, 22, 5);
	Misc_BuildImage (MonthNames[2], 40, 54, 22, 5);
	Misc_BuildImage (MonthNames[3], 40, 48, 22, 5);
	Misc_BuildImage (MonthNames[4], 40, 42, 22, 5);
	Misc_BuildImage (MonthNames[5], 40, 36, 22, 5);
	Misc_BuildImage (MonthNames[6], 40, 30, 22, 5);
	Misc_BuildImage (MonthNames[7], 40, 24, 22, 5);
	Misc_BuildImage (MonthNames[8], 40, 18, 22, 5);
	Misc_BuildImage (MonthNames[9], 40, 12, 22, 5);
	Misc_BuildImage (MonthNames[10], 40, 6, 22, 5);
	Misc_BuildImage (MonthNames[11], 40, 0, 22, 5);

	Misc_BuildImage (DateNumbers[0], 172.0, 14.0, 10.0, 17.0);
	Misc_BuildImage (DateNumbers[1], 65.0, 14.0, 8.0, 17.0);
	Misc_BuildImage (DateNumbers[2], 76.0, 14.0, 10.0, 17.0);
	Misc_BuildImage (DateNumbers[3], 88.0, 14.0, 9.0, 17.0);
	Misc_BuildImage (DateNumbers[4], 100.0, 14.0, 10.0, 17.0);
	Misc_BuildImage (DateNumbers[5], 112.0, 14.0, 10.0, 17.0);
	Misc_BuildImage (DateNumbers[6], 124.0, 14.0, 10.0, 17.0);
	Misc_BuildImage (DateNumbers[7], 136.0, 14.0, 10.0, 17.0);
	Misc_BuildImage (DateNumbers[8], 148.0, 14.0, 10.0, 17.0);
	Misc_BuildImage (DateNumbers[9], 160.0, 14.0, 10.0, 17.0);

	Misc_BuildImage (YearNumbers[0], 12.0, 8.0, 6.0, 5.0);
	Misc_BuildImage (YearNumbers[1], 0.0, 20.0, 2.0, 5.0);
	Misc_BuildImage (YearNumbers[2], 2.0, 20.0, 5.0, 5.0);
	Misc_BuildImage (YearNumbers[3], 7.0, 20.0, 5.0, 5.0);
	Misc_BuildImage (YearNumbers[4], 12.0, 20.0, 5.0, 5.0);
	Misc_BuildImage (YearNumbers[5], 0.0, 14.0, 5.0, 5.0);
	Misc_BuildImage (YearNumbers[6], 5.0, 14.0, 6.0, 5.0);
	Misc_BuildImage (YearNumbers[7], 11.0, 14.0, 5.0, 5.0);
	Misc_BuildImage (YearNumbers[8], 0.0, 8.0, 6.0, 5.0);
	Misc_BuildImage (YearNumbers[9], 6.0, 8.0, 6.0, 5.0);
	Misc_BuildImage (YearColon, 18.0, 25.0, 1.0, 5.0);

	Misc_BuildImage (clockbase, 64, 72, 64, 64);

	[DigitalNumbers[1] getSize:&oneSize];
	[DigitalNumbers[2] getSize:&twoSize];
	colonPosition.x = oneSize.width + twoSize.width + 7.0;

	timedEntry = 0;
	if (keepingTime)
	{
		[self startClock:self];
	}

	return self;
}


- initFrame:(const NXRect *)frameRect
{
		
	[super initFrame:frameRect];
	hidden=NO;
	keepingTime=NO;
	[self _setUp];
	return self;

}

- awake
{
	id ret = [super awake];
	[self _setUp];
	return ret;
}

- awakeFromNib
{
	id ret = [super awake];
	[self _setUp];
	return ret;
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{
NXPoint        imageOrigin;
NXSize         size, theSize, tensSize = {0.0, 0.0}, onesSize, twoSize;
id             imageAyear, imageByear, imageCyear, imageDyear;
float          width, widthA, widthB, widthC;
float          imageAdjust;
int            currentYear, hrs;

	if (hidden) {
		PSsetgray(NX_LTGRAY);
		NXRectFill(&bounds);
	}
	
	[DigitalNumbers[1] getSize:&onesSize];
	[DigitalNumbers[2] getSize:&twoSize];

	if (!militaryTime)
		colonPosition.x = onesSize.width + twoSize.width + 7.0;
	else
		colonPosition.x = 30;

	if (showYear)
	{
		imageAdjust = 5;
		colonPosition.y = 51;
	}
	else
	{
		imageAdjust = 0;
		colonPosition.y = 46;
	}


	imageOrigin.x = 0;
	imageOrigin.y = 0 + imageAdjust;	//(0)
	[clockbase composite:NX_COPY toPoint:&imageOrigin];


	if (militaryTime)
	{
		hrs = hours;
	}
	else
	{
		hrs = hours % 12;
		if (!hrs)	hrs = 12;
	}
	
	[imageAM getSize:&size];
	imageOrigin.x = 44;
	imageOrigin.y = 48 + imageAdjust;	//(48)
	if (!militaryTime)
	{
		if (meridian)
		{
			imageOrigin.x = 45;
			[imagePM composite:NX_COPY toPoint:&imageOrigin];
		}
		else
			[imageAM composite:NX_COPY toPoint:&imageOrigin];
	}

	imageOrigin = colonPosition;
	if (hrs / 10 || militaryTime)
		[DigitalNumbers[hrs / 10] getSize:&tensSize];


	[DigitalNumbers[hrs % 10] getSize:&onesSize];
	imageOrigin.x -= tensSize.width + onesSize.width;

	if (hrs / 10 || militaryTime)
	{
		[DigitalNumbers[hrs / 10] composite:NX_COPY toPoint:&imageOrigin];
		imageOrigin.x += tensSize.width;
	}

	[DigitalNumbers[hrs % 10] composite:NX_COPY toPoint:&imageOrigin];
	imageOrigin.x += onesSize.width;

	[[imageColon getSize:&size] composite:NX_COPY toPoint:&imageOrigin];
	imageOrigin.x += size.width;

	[[DigitalNumbers[minutes / 10] getSize:&size] composite:NX_COPY toPoint:&imageOrigin];
	imageOrigin.x += size.width;
	[DigitalNumbers[minutes % 10] composite:NX_COPY toPoint:&imageOrigin];

	imageOrigin.x = 21;
	imageOrigin.y = 34 + imageAdjust;	//(34)
	[DayNames[weekday] composite:NX_COPY toPoint:&imageOrigin];

	imageOrigin.x = 19;
	imageOrigin.y = 9 + imageAdjust;	//(9)
	[MonthNames[month] composite:NX_COPY toPoint:&imageOrigin];

	tensSize.width = 0.0;
	tensSize.height = 0.0;


	imageOrigin.x = 30;
	imageOrigin.y = 15 + imageAdjust; //(15)
	if (date / 10)
		[DateNumbers[date / 10] getSize:&tensSize];
	[DateNumbers[date % 10] getSize:&onesSize];
	imageOrigin.x -= (tensSize.width + onesSize.width) / 2;
	if (date / 10)
		[DateNumbers[date / 10] composite:NX_COPY toPoint:&imageOrigin];
	imageOrigin.x += tensSize.width + 1;
	[DateNumbers[date % 10] composite:NX_COPY toPoint:&imageOrigin];

	//Draw the year
	if (showYear)
	{
		currentYear = [self year] + 1900;
		imageAyear = YearNumbers[currentYear / 1000];
		currentYear = currentYear % 1000;

		imageByear = YearNumbers[currentYear / 100];
		currentYear = currentYear % 100;

		imageCyear = YearNumbers[currentYear / 10];
		currentYear = currentYear % 10;

		imageDyear = YearNumbers[currentYear];

		[imageAyear getSize:&theSize];
		widthA = theSize.width;
		[imageByear getSize:&theSize];
		widthB = theSize.width;
		[imageCyear getSize:&theSize];
		widthC = theSize.width;
		[imageDyear getSize:&theSize];
		width = widthA + widthB + widthC + theSize.width;

		imageOrigin.x = 32 - (width / 2.0);
		imageOrigin.y = 0;
		[imageAyear composite:NX_COPY toPoint:&imageOrigin];
		imageOrigin.x = imageOrigin.x + widthA;
		[imageByear composite:NX_COPY toPoint:&imageOrigin];
		imageOrigin.x = imageOrigin.x + widthB;
		[imageCyear composite:NX_COPY toPoint:&imageOrigin];
		imageOrigin.x = imageOrigin.x + widthC;
		[imageDyear composite:NX_COPY toPoint:&imageOrigin];
	}
	return self;
}

- setSeconds:(int)theSeconds
{
	seconds = theSeconds;
	return self;
}

- setMinutes:(int)theMinutes
{
	minutes = theMinutes;
	return self;
}

- setHours:(int)theHours
{
	hours = theHours;
	return self;
}

- setWeekday:(int)theWeekday
{
	weekday = theWeekday;
	return self;
}

- setDate:(int)theDate
{
	date = theDate;
	return self;
}

- setMonth:(int)theMonth
{
	month = theMonth;
	return self;
}

- setYear:(int)theYear
{
	year = theYear;
	return self;
}

- setMeridian:(int)theMeridian
{
	meridian = theMeridian;
	return self;
}

- takeMinutesFrom:sender
{
	[self setMinutes:[sender intValue]];
	[self display];
	return self;
}

- takeHoursFrom:sender	
{
int            localhours = [sender intValue];

	localhours %= 24;
	if (localhours <= 12)
	{
		[self setMeridian:0];
	}
	else
	{
		[self setMeridian:1];
	}
	[self setHours:localhours];
	[self display];
	return self;
}
	
- takeWeekdayFrom:sender
{
	[self setWeekday:[sender intValue]];
	[self display];
	return self;
}

- takeDateFrom:sender
{
	[self setDate:[sender intValue]];
	[self display];
	return self;
}

- takeMonthFrom:sender
{
	[self setMonth:[sender intValue]];
	[self display];
	return self;
}

- setTime: (struct tm*)theTime
{
	seconds = theTime->tm_sec;
	minutes = theTime->tm_min;
	hours = theTime->tm_hour;
	if (hours <= 12)
	{
		meridian = 0;
	}
	else
	{
		meridian = 1;
	};
	date = theTime->tm_mday;
	month = theTime->tm_mon;
	year = theTime->tm_year;
	weekday = theTime->tm_wday;
	return self;
};



- (const char *)getInspectorClassName
{
	return "MiscClockViewInspector";
}

- (int)year
{
	return year;
}

- (int)month
{
	return month;
}

- (int)weekday
{
	return weekday;
}

- (int)date
{
	return date;
}

- (int)hours
{
	return hours;
}

- (int)minutes
{
	return minutes;
}

- (int)seconds
{
	return seconds;
}


- (BOOL)militaryTime
{
	return militaryTime;
}

- (BOOL)showYear
{
	return showYear;
}

- setShowYear:(BOOL)state
{
	showYear = state;
	return self;
}


- setMilitaryTime:(BOOL)state
{
	militaryTime = state;
	return self;
}


- (BOOL)keepingTime
{
	return keepingTime;
}


- setKeepingTime:(BOOL)yesno
{
	keepingTime = yesno;
	return self;
}

- read:(NXTypedStream *) stream
{
	int myVersion = NXTypedStreamClassVersion (stream,[self name]);

	[super read:stream];
	if (myVersion < 2)
	{
		NXReadTypes (stream, "iiiiiiiiii", &seconds, &minutes, &hours,
		&date, &month, &year, &weekday, &meridian, &showYear, &militaryTime);
	}
	else
	{
		NXReadTypes (stream, "iiiiiiiicc", &seconds, &minutes, &hours,
		&date, &month, &year, &weekday, &meridian, &showYear, &militaryTime);
	}
	if (myVersion < 1)
	{
		keepingTime = NO;
	}
	else if (myVersion == 1)
	{
		NXReadType (stream, "i", &keepingTime);
	}
	else
	{
		NXReadType (stream, "c", &keepingTime);
	}
	if (myVersion > 2) {
		NXReadType (stream, "c", &hidden);
	} else {
		hidden = NO;
	}
	return self;
}

- write:(NXTypedStream *) stream
{
	[super write:stream];
	NXWriteTypes (stream, "iiiiiiiicc", &seconds, &minutes, &hours,
	&date, &month, &year, &weekday, &meridian, &showYear, &militaryTime);
	NXWriteType (stream, "c", &keepingTime);
	NXWriteType (stream, "c", &hidden);
	return self;
}

- setHide:(BOOL)hide
{
   hidden = hide;

   return self;
}

- (BOOL)isHidden
{
   return hidden;
}


void 
Animate (timedEntry, now, self)
	DPSTimedEntry  timedEntry;
	double         now;
	id             self;
{
	[(id)self ticktock];
}

- ticktock
{
struct timeval tp;
struct timezone tzp;
struct tm     *tv;

	gettimeofday (&tp, &tzp);
	tv = localtime (&tp.tv_sec);
	[self setTime:tv];
	[self display];
	return self;
}

- startClock:sender
{
	if (!keepingTime)
	{
		[self ticktock];
		timedEntry = DPSAddTimedEntry (60, Animate, (void *)self, NX_MODALRESPTHRESHOLD);
		keepingTime = YES;
		NXPing ();
	}
	return self;
}

- stopClock:sender
{
	if (timedEntry)
	{
		DPSRemoveTimedEntry (timedEntry);
		[self ticktock];
		keepingTime = NO;
		timedEntry = 0;
	}

	return self;
}

- free
{
   int i;
	
	[imageA free];
	[imageP free];
	for(i=0;i<10;i++)
		[DigitalNumbers[i] free];
	[imageColon free];
	[imageAM free];
	[imagePM free];
	
	for(i=0;i<7;i++)
		[DayNames[i] free];
	for(i=0;i<12;i++)
   	[MonthNames[i] free];
	for(i=0;i<10;i++)
		[DateNumbers[i] free];
	for(i=0;i<10;i++)
		[YearNumbers[i] free];
	[YearColon free];
	[clockbase free];
	[theImage free];

	if (timedEntry != NULL)
		DPSRemoveTimedEntry (timedEntry);
	return[super free];
}

- setToCurrentTime:sender
{
struct timeval		tp;
struct timezone	tzp;
struct tm     		*tv;

	gettimeofday (&tp, &tzp);
	tv = localtime (&tp.tv_sec);
	[self setTime:tv];
	[self display];
	
	return self;
}

@end
